import random
from pyglet.gl import *
import data

try:
    import lepton
    from lepton import controller, renderer, emitter, domain
except ImportError:
    import warnings
    warnings.warn('Lepton particle engine not found, particles disabled')
    lepton = None


class BubbleEmitter:
    """Bubble emitter that emits bubbles from a sprite from it's
    collision position
    """

    VELOCITY_DEVIATION = 20

    def __init__(self, sprite, speed, rate, sizes, spread=2):
        if lepton is None:
            self.sprite = None
            return
        self.sprite = sprite
        self.rate = rate
        self.emitter = emitter.StaticEmitter(
            rate,
            template=lepton.Particle(
                position=(400,300,0),
                velocity=(speed, self.VELOCITY_DEVIATION),
                color=(1, 1, 1, 1),
                ),
            deviation=lepton.Particle(
                velocity=(spread, self.VELOCITY_DEVIATION),
                ),
            size=[(x,y*2,0) for x,y in sizes], # XXX why *2???
            )
        bubble_effect.add_emitter(self.emitter)

    def update(self, dt):
        if self.sprite is not None:
            position = self.sprite.collision_position
            self.emitter.template.position = (position.x, position.y, 0)
            self.emitter.rate = max(1 + random.gauss(0, self.rate), 0)

    def kill(self):
        if self.sprite is not None:
            bubble_effect.remove_emitter(self.emitter)
            self.sprite = None # quicken gc, and mark as killed

    __del__ = kill # just in case kill isn't called


class BubbleEffect:
    
    def __init__(self):
        self.bubble_tex = data.texture('bubble.png')
        self.group = lepton.ParticleGroup(
            controllers=[
                controller.Lifetime(2),
                controller.Movement(damping=(1.0, 0.9, 0)),
                controller.Gravity((0, 200, 0)),
                controller.Fader(max_alpha=0.5, fade_out_start=0, fade_out_end=2),
                controller.Collector(water_domain, collect_inside=False),
                ],
            renderer=renderer.BillboardRenderer())

    def draw(self):
        glEnable(self.bubble_tex.target)
        glBindTexture(self.bubble_tex.target, self.bubble_tex.id)
        self.group.draw()
        glDisable(self.bubble_tex.target)

    def add_emitter(self, emitter):
        self.group.bind_controller(emitter)

    def remove_emitter(self, emitter):
        self.group.unbind_controller(emitter)


class splash_effect:

    VELOCITY_DEVIATION = 0.1
    COLORS = [
        (0.1, 0.5, 0.3, 1.0),
        (0.1, 0.5, 0.3, 1.0),
        (1.0, 1.0, 1.0, 1.0),
        ]

    splash_tex = data.texture('bubble.png')
    
    if lepton is not None:
        group = lepton.ParticleGroup(
            controllers=[
                controller.Lifetime(1.0),
                controller.Movement(),
                controller.Gravity((0, -300, 0)),
                controller.Fader(max_alpha=0.5, fade_out_start=0.8, fade_out_end=1.0),
                controller.Growth(-40),
            ],
            renderer=renderer.BillboardRenderer())

    @classmethod
    def splash(cls, position, particles, velocity, spread, size):
        if lepton is None:
            return
        splasher = emitter.StaticEmitter(
            template=lepton.Particle(
                position=(position.x, position.y, 0),
                velocity=(0, velocity, 0),
                size=(size, size * 2, 0) # XXX why *2???
                ),
            deviation=lepton.Particle(
                velocity=(spread, velocity * cls.VELOCITY_DEVIATION, 0),
                ),
            color=cls.COLORS,
            )
        splasher.emit(particles, cls.group)

    @classmethod
    def draw(cls):
        glEnable(cls.splash_tex.target)
        glBindTexture(cls.splash_tex.target, cls.splash_tex.id)
        cls.group.draw()
        glDisable(cls.splash_tex.target)


def init(game):
    """Initialize the particle effects"""
    global bubble_effect, water_domain
    if lepton is not None:
        try:
            Box = domain.Box # lepton 0.6a
        except AttributeError:
            Box = domain.AABox # lepton svn
        water_domain = Box((0,0,0), (game.width, game.water_level * 1.03, 0))
        bubble_effect = BubbleEffect()

def update(dt):
    """Update all the particle effects"""
    if lepton is not None:
        lepton.default_system.update(dt)

def draw():
    """Draw all particle effects"""
    global bubble_effect
    if lepton is not None:
        bubble_effect.draw()
        splash_effect.draw()

